﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using System.Web.Script.Serialization;
using SinBiota.Model.Business.PersistenceServices.Interfaces;
using SinBiota.Model.Entities;

namespace Sinbiota.Web.Models
{
    public class SpecimenListModel
    {
        public IEnumerable<SpecimenModel> SpecimenList { get; private set; }
        public string JsonSpecimenList { get; set; }

        public SpecimenListModel(IEnumerable<Specimen> specimenList)
        {
            SpecimenList = specimenList.Select(sp => new SpecimenModel(sp));
            var serializer = new JavaScriptSerializer();
            JsonSpecimenList = serializer.Serialize(SpecimenList);
        }
        
    }
    public class SpecimenListFullModel
    {
        public IEnumerable<SpecimenFullModel> SpecimenList { get; private set; }
        public string JsonSpecimenList { get; set; }
        public TaxonTreeNode RootNode { get; set; }

        public SpecimenListFullModel(IEnumerable<Specimen> specimenList, ITaxonPersistenceServices taxonPersistenceServices, bool serialize = true)
        {
            SpecimenList = specimenList.Select(sp => new SpecimenFullModel(sp, taxonPersistenceServices));
            if (serialize)
            {
                var serializer = new JavaScriptSerializer();
                JsonSpecimenList = serializer.Serialize(SpecimenList);
            }

            // Now build the taxon tree:
            RootNode = new TaxonTreeNode(0,"Root","Root");
            foreach (var specimen in SpecimenList)
            {
                var currentNode = specimen.FullTaxonomicClassificationArray.Aggregate(RootNode, AddNode);
                // Add the current species in this node:
                currentNode.Specimens.Add(specimen);
                currentNode.NumberOfLeaves++;
            }
        }

        private static TaxonTreeNode AddNode(TaxonTreeNode currentNode, NameRank nameRank)
        {
            // get child in the tree: is it the child of the current node if it exists, otherwise create a new taxon tree node:
            var child = currentNode.GetChild(nameRank.Id);
            if (child == null)
            {
                child = new TaxonTreeNode(nameRank.Id, nameRank.Name, nameRank.Rank, currentNode);
                currentNode.Children.Add(child);
            }
            // increase the number of leaves:
            currentNode.NumberOfLeaves++;
            return child;
            
        }
           
    }

    public class SpecimenFullModel : SpecimenModel
    {
        public IDictionary<string, string> FullTaxonomicClassification;
        public IList<NameRank> FullTaxonomicClassificationArray;
        public SpecimenFullModel(Specimen sp, ITaxonPersistenceServices taxonPersistenceServices) : base(sp)
        {
            var ancestors = taxonPersistenceServices.FindAncestors(sp.TaxonomicClassification.Taxon);
            FullTaxonomicClassification = ancestors.ToDictionary(x => x.Rank, x => x.Name);
            FullTaxonomicClassificationArray = ancestors.Select(taxon => new NameRank(taxon)).ToList();
            FullTaxonomicClassificationArray.Add(new NameRank(sp.TaxonomicClassification.Taxon));
        }
    }

    public class NameRank
    {
        public NameRank(int id, string name, string rank)
        {
            Id = id;
            Name = name;
            Rank = rank;
        }

        public NameRank(Taxon taxon)
        {
            Id = taxon.Id;
            Name = taxon.Rank.Contains("species") ? taxon.ScientificName() : taxon.Name;
            Rank = taxon.Rank;
        }

        public int Id { get; set; }
        public string Name { get; set; }
        public string Rank { get; set; }
    }


    public class TaxonTreeNode
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Rank { get; set; }
        public TaxonTreeNode Parent { get; set; }
        public IList<TaxonTreeNode> Children { get; set; }
        public IList<SpecimenModel> Specimens { get; set; }
        public int NumberOfLeaves { get; set; }

        public TaxonTreeNode(int id, string name, string rank, TaxonTreeNode parent = null)
        {
            Id = id;
            Name = name;
            Rank = rank;
            Parent = parent;
            NumberOfLeaves = 0;
            Children = new List<TaxonTreeNode>();
            Specimens = new List<SpecimenModel>();
        }
        public TaxonTreeNode GetChild(int id)
        {
            return Children.FirstOrDefault(taxonTree => taxonTree.Id == id);
        }
    }

    public class SpecimenModel
    {
        public SpecimenModel()
        {
        }

        public SpecimenModel(Specimen sp)
        {
            Id = sp.Id;
            Count = sp.Count;
            TaxonomicClassification = sp.TaxonomicClassification.Taxon.ScientificName();
            EOLTaxonId = sp.TaxonomicClassification.EOLTaxonId;
            TaxonomicClassificationId = sp.TaxonomicClassification.Id;
            TaxonId = sp.TaxonomicClassification.Taxon.Id;
            var record = sp.DepositaryUnitRecords.DefaultIfEmpty(null).First();
            if (record == null)
            {
                DepositaryUnitRecordId = -1;
                DepositaryUnit = "";
                RecordUniqueId = "";
            }
            else
            {
                DepositaryUnitRecordId = record.Id;
                DepositaryUnit = record.DepositaryUnit.Name;
                RecordUniqueId = record.UniqueId;
            }
            var group = sp.TaxonomicClassification.LegacyTaxonomicGroup;
            LegacyTaxonomicGroup = group == null ? "" : group.Name;
            LegacyTaxonomicGroupClassification = group == null ? "" : group.LegacyTaxonomyLocalizedToListPairs();

            var classification = sp.TaxonomicClassification.LegacyTaxonomicClassification;
            LegacyTaxonomicClassification = String.IsNullOrWhiteSpace(classification) ? "" : sp.TaxonomicClassification.LegacyTaxonomyLocalizedRequiredRanksToListPairs();

        }

        public int Id { get; set; }
        public int? Count { get; set; }
        public string TaxonomicClassification { get; set; }
        public int TaxonomicClassificationId { get; set; }
        public string EOLTaxonId { get; set;}
        public int TaxonId { get; set; }
        public int DepositaryUnitRecordId {get; set;}
        public string DepositaryUnit { get; set; }
        public string RecordUniqueId { get; set; }

        public string LegacyTaxonomicGroup { get; set; }
        public object LegacyTaxonomicGroupClassification { get; set; }
        public object LegacyTaxonomicClassification { get; set; }

    }

    public class SpecimenFromSheet
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Rank { get; set; }
        public int? Count { get; set; }
        // If appending a taxon in the id above:
        public bool Append { get; set; }
        public string AppendName { get; set; }
        public string AppendRank { get; set; }
        public string Reference { get; set; }
        // Depositary unit info:
        public string DepositaryUnit { get; set; }
        public string RecordId { get; set; }
    }

}